/**
在07_TS中，抽象类和抽象方法的使用说明总结如下：
  1. 抽象类的定义
  - 抽象类是一个不能被实例化的类，用于定义其他类的共同特征和行为。它可以包含抽象方法和具体方法。
  - 抽象类通常使用 `abstract` 关键字进行定义。

  2. 抽象方法的定义
  - 抽象方法是没有具体实现的方法，仅包含方法的声明，使用 `abstract` 关键字修饰。
  - 子类必须实现所有的抽象方法，否则该子类也必须被声明为抽象类。

  3. 抽象类的特点
  - 抽象类可以包含：
    - 抽象方法：没有实现的方法，必须在子类中实现。
    - 具体方法：有实现的方法，可以被子类继承或重写。
    - 成员变量：可以包含实例变量和静态变量。

  4. 抽象类的用途
  - 抽象类用于提供一个统一的接口，让不同的子类根据具体需求实现特定的功能。
  - 适用于需要共享代码和行为的类层次结构。

  5. 示例代码
  // 抽象类
  abstract class Animal {
      // 抽象方法
      abstract void sound();

      // 具体方法
      void eat() {
          System.out.println("动物在吃东西");
      }
  }

  // 子类继承抽象类
  class Dog extends Animal {
      // 实现抽象方法
      @Override
      void sound() {
          System.out.println("狗叫：汪汪");
      }
  }

  class Cat extends Animal {
      // 实现抽象方法
      @Override
      void sound() {
          System.out.println("猫叫：喵喵");
      }
  }
  6. 使用注意事项
  - 抽象类不能被实例化，尝试实例化抽象类会导致编译错误。
  - 抽象类可以有构造函数，供子类调用。
  - 抽象类可以实现接口，但不能被实例化。

  7. 总结
  抽象类和抽象方法是面向对象编程中的重要概念，能够帮助设计灵活的类层次结构，鼓励代码重用和接口规范。通过抽象类，开发者可以定义通用行为，而具体的实现则留给子类完成。
 */
abstract class Shape {
  // getArea方法只有声明没有实现体
  // 实现让子类自己实现
  // 可以将getArea方法定义为抽象方法: 在方法的前面加abstract
  // 抽象方法必须出现在抽象类中, 类前面也需要加abstract
  abstract getArea()
}

class Rectangle extends Shape {
  constructor(public width: number, public height: number) {
    super()
  }

  getArea() {
    return this.width * this.height
  }
}

class Circle extends Shape {
  constructor(public radius: number) {
    super()
  }

  getArea() {
    return this.radius * this.radius * 3.14
  }
}

// Triangle: 三角形
class Triangle extends Shape {
  constructor(public width: number, public height: number) {
    super()
  }

  getArea() {
    return this.width * this.height / 2
  }
}

// 通用的函数
function calcArea(shape: Shape) {
  return shape.getArea()
}

calcArea(new Rectangle(10, 20))
calcArea(new Circle(5))
calcArea(new Triangle(10, 20))

// 在Java中会报错: 不允许
calcArea({ getArea: function() {} })

export {}